/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package server;

import java.io.*;
import java.net.Socket;
import model.Message;
import model.RevisionController;
import util.Utilities;

/**
 *
 * @author Asus
 */
public class ServerController extends Thread{
    private Server mServer;
    private Socket mSocket;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    
    public ServerController(Server server, Socket socket) {
        mServer = server;
        mSocket = socket;

        System.out.println("Done Creating controller for " + socket.getInetAddress().toString());
    }
    
    @Override
    public void run() {
        try {
            mInputStream    = mSocket.getInputStream();
            mOutputStream   = mSocket.getOutputStream();
            System.out.println("[Server Handler] I/O Stream managed");
            while (!mSocket.isClosed()) {
                try {
                    // baca message type
                    int messageType     = mInputStream.read();
                    int messageLength   = 0;

                    if (messageType == Message.MSG_KEEP_ALIVE || messageType == -1) continue;

                    // baca message length
                    messageLength = (mInputStream.read() + 256) % 256;
                    messageLength = (messageLength << 8) + (mInputStream.read() + 256) % 256;
                    messageLength = (messageLength << 8) + (mInputStream.read() + 256) % 256;
                    messageLength = (messageLength << 8) + (mInputStream.read() + 256) % 256;

                    // baca binary
                    byte[] ret = new byte[messageLength - 5];
                    int totalRead = 0;
                    if (messageLength > 4096) {
                        byte[] buffer = new byte[4096];
                        int read;
                        
                        while (totalRead < messageLength - 5 && (read = mInputStream.read(buffer)) > 0) {
                            for (int i = 0; i < read; ++i) {
                                ret[totalRead + i] = buffer[i];
                            }

                            totalRead += read;
                        }
                    } else {
                        totalRead = mInputStream.read(ret);
                    }


                    // handle message
                    // kenapa -5 ? karena sudah dikurangi message length dan message type
                    if (totalRead != messageLength - 5) {
                        System.out.println("[Server Handler] Message error, read " + totalRead + " bytes, expected " + (messageLength - 5));
                    } else {
                        Object[] param = Message.readMessage(messageType, messageLength, ret);

                        switch (messageType) {
                            case Message.MSG_KEEP_ALIVE:

                                break;
                            case Message.MSG_FILEINFO:
                                handleMetadataMessage((String)param[0]);
                                break;

                            case Message.MSG_FILEINFO_RESP:
                                handleMetadataResponseMessage((String)param[0], (byte[])param[1]);
                                break;

                            case Message.MSG_UPLOAD:
                                handleUploadMessage((String)param[0], (byte[])param[1]);
                                break;

                            case Message.MSG_DOWNLOAD:
                                handleDownloadMessage((String)param[0], (String)param[1]);
                                break;

                            case Message.MSG_DELETE:
                                handleDeleteMessage((String)param[0]);
                                break;
                        }
                    }
                } catch (IOException iEx) {
                    
                }
            }

            System.out.println("[Server Handler] handler closed for " + mSocket.getInetAddress().toString());
            mInputStream.close();
            mOutputStream.close();
        } catch (IOException iEx) {
            
        }
    }

    private void handleMetadataMessage(String path) {
        try {
            Object[] param = new Object[2];

            byte[] res = RevisionController.getVersionControl(path).toSend();

            param[0] = path;
            param[1] = res;

            Message message = new Message(Message.MSG_FILEINFO_RESP, param);
            Message.sendMessage(mSocket, message);
        } catch (IOException iEx) {
            
        }
    }

    private void handleMetadataResponseMessage(String path, byte[] binary) {
        RevisionController version = RevisionController.createFromByte(binary);

        version.setRevisionToFile(path, true);
    }

    private void handleDownloadMessage(String localPath, String remotePath) {
        try {
            byte[] res = Utilities.getFileByte(remotePath);

            Object[] param = new Object[2];
            param[0] = localPath;
            param[1] = res;

            Message message = new Message(Message.MSG_DOWNLOAD_RESP, param);
            Message.sendMessage(mSocket, message);
        } catch (IOException iEx) {
            
        }
            
    }
    
    private void handleUploadMessage(String path, byte[] binary) {
        try {
            System.out.println("[Server Handler] Handling upload message");
            File file = new File(path);
            if (binary.length == 0) {
                file.mkdirs();
            } else {
                if (file.getParentFile() != null && !file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
                }
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));

                bos.write(binary);

                bos.close();
            }
        } catch (IOException iEx) {
            
        }
    }

    private void handleDeleteMessage(String path) {
        File file = new File(path);

        if (file.exists()) {
            file.delete();
        }
    }
    
}
